import {Component} from 'react';
import PropTypes from 'prop-types';

export default class Fetching extends Component {
  constructor(props) {
    super(props);
    this.state = {
      data: null,
      loading: false,
      error: false,
    };
  }
  async load() {
    const {fetch} = this.props;
    this.setState({
      loading: true,
      error: null,
    });
    try {
      const data = fetch && typeof fetch === 'function' && (await fetch());
      if (this.unmounted) {
        return;
      }
      this.setState({
        data: data,
      });
    } catch (error) {
      this.setState({error});
    } finally {
      if (this.unmounted) {
        return;
      }
      this.setState({loading: false});
    }
  }
  componentDidMount() {
    this.load();
  }
  reload() {
    this.setState({
      loading: true,
      error: null,
      data: null
    }, ()=>{
      this.load()
    })
  }
  retry() {
    this.load();
  }
  componentWillUnmount() {
    this.unmounted = true;
  }
  genComponent(element, props) {
    return typeof element === 'function' ? element(props) : element;
  }
  render() {
    const {children, loading: loadingFn, error: errorFn} = this.props;

    const {loading, error, data} = this.state;

    const comp = this.genComponent(children, {
      data,
      loading,
      error,
      retry: this.retry.bind(this),
    });

    const loadingComp = this.genComponent(loadingFn, {loading});

    const errorComp = this.genComponent(errorFn, {
      error,
      retry: this.retry.bind(this),
    });

    if (error && errorComp) {
      return errorComp;
    }
    if (loading && loadingComp) {
      return loadingComp;
    }
    return comp;
  }
}

Fetching.propTypes = {
  fetch: PropTypes.func,
  error: PropTypes.oneOfType([PropTypes.element, PropTypes.func]),
  loading: PropTypes.oneOfType([PropTypes.element, PropTypes.func]),
};
